#include "TokenGenerator.h"
#include "HeadFile.h"
#include "Token.h"

#include <numeric>
#include <cassert>


CTokenGenerator::CTokenGenerator(CHeadFile* InContext)
{
    Context=InContext;
}

void CTokenGenerator::GenerateTokens()
{
    while(CharIndex<Context->Content.GetLength())
    {
        if(!TryCreateToken())
        {
            return;
        }
    }

    //add EndOfFile Token
    Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::EndOfFile,SFilePosition(LineIndex,ColumnIndex,1)));

}

bool CTokenGenerator::TryCreateToken()
{
    auto CurrentChar=GetCurrentChar();
    switch(CurrentChar)
    {
        case U'\0':
        {
           
            //add end of file token
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::EndOfFile,SFilePosition(LineIndex,ColumnIndex,1)));
            return true;     
        }
        case U' ':case U'\t':case U'\r':case U'\n':
        {
           
            //skip space
            GotoNextChar();
            return true;
        }
        case U'*':
        {
           {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Multiply,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
           }
            return true;
        }
        case U'/':
        {
            if(GetNextChar()==U'/')
            {
                //skip comment
                while(GetCurrentChar()!=U'\n' &&  GetCurrentChar()!=U'\0'  )
                {
                    GotoNextChar();
                }
                return true;
            }
            else if(GetNextChar()==U'*')
            {
            
                //skip comment
                GotoNextChar();
                while(GetCurrentChar()!=U'*' || GetNextChar()!=U'/')
                {
                    GotoNextChar();
                }
                GotoNextChar();
                GotoNextChar();
                return true;
            }

            else 
            {
            
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Unknow,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
                return true;
            }
        }

        case U'"':
        {
                                                   
            //literal string
            C32String LiteralString;
            GotoNextChar();
            while(GetCurrentChar()!=U'"')
            {
                if(GetCurrentChar()==U'\0')
                {
                    Context->RaiseError(LineIndex,ColumnIndex,1,U"Literal string not end");
                    return false;
                }

                char32_t LiteralChar=GetCurrentChar();
                if(LiteralChar==U'\\')
                {
                    auto EscapeChar=ReadEscapeChar();
                    if(!EscapeChar.has_value())
                    {
                        return false;
                    }
                    LiteralChar=EscapeChar.value();
                }

                LiteralString+=LiteralChar;
                GotoNextChar();
            }
            GotoNextChar();
            Context->Tokens.push_back(
                    std::make_shared<CToken>(
                        LiteralString
                        ,SFilePosition(LineIndex,ColumnIndex,LiteralString.GetLength()+2)
                        )
            );
            return true;                                            

        }

        case U'\'':
        {                    
            //literal char
            GotoNextChar();
            if(GetCurrentChar()==U'\'')
            {
                Context->RaiseError(LineIndex,ColumnIndex,1,U"Literal char not end");
                return false;  
            }
            char32_t LiteralChar=GetCurrentChar();
            if(LiteralChar==U'\\')
            {
                auto EscapeChar=ReadEscapeChar();
                if(!EscapeChar.has_value())
                {
                    return false;
                }
                LiteralChar=EscapeChar.value();
            }
            
            GotoNextChar();
            char32_t NextChar=GetCurrentChar();
            if(NextChar!=U'\'')
            {
                Context->RaiseError(LineIndex,ColumnIndex,1,U"Literal char not end");
                return false;
            }
            GotoNextChar();
            Context->Tokens.push_back(std::make_shared<CToken>(LiteralChar,SFilePosition(LineIndex,ColumnIndex,3)));
            return true;                                        
        }

        case U'?':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Question,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }


        case U'(':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::LeftParentheses,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U')':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RightParentheses,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U'{':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::LeftBrace,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U'}':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RightBrace,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U'[':
        {   
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::LeftBracket,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U']':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RightBracket,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U',':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Comma,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U';':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Semicolon,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U':':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Colon,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U'.':
        {
           
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Dot,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }

        case U'!':
        {
           
            if(GetNextChar()==U'=')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::NotEqual,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            else
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::NotOperator,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
                return true;
            }
        }

        case U'=':
        {
           
            if(GetNextChar()==U'=')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Equal,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            if(GetNextChar()==U'>')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::LambdaOperator,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            else
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Assign,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
                return true;
            }
        }

        case U'<':
        {
           
            if(GetNextChar()==U'=')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::LessEqual,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            else
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Less,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
                return true;
            }
        }

        case U'>':
        {
           
            if(GetNextChar()==U'=')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::GreaterEqual,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            else
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Greater,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
                return true;
            }
        }

        case U'+':
        {
           
            if(GetNextChar()==U'+')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::PlusPlus,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            else if(GetNextChar()==U'=')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::PlusAssign,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }

            else
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Plus,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
                return true;
            }
        }

        case U'-':
        {
           
            if(GetNextChar()==U'-')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::MinusMinus,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            else if(GetNextChar()==U'=')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::MinusAssign,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }
            else if(GetNextChar()==U'>')
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Arrow,SFilePosition(LineIndex,ColumnIndex,2)));
                GotoNextChar();
                GotoNextChar();
                return true;
            }

            else
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Minus,SFilePosition(LineIndex,ColumnIndex,1)));
                GotoNextChar();
                return true;
            }
        }
        case U'~': 
        {
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Tilde,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }     
        
        case U'&':
        {
            Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::And ,SFilePosition(LineIndex,ColumnIndex,1)));
            GotoNextChar();
            return true;
        }



        case U'0':
        case U'1':
        case U'2':
        case U'3':
        case U'4':
        case U'5':
        case U'6':
        case U'7':
        case U'8':
        case U'9':
        {
            C32String NumberString;
            C32String NumberStringAfterDot;
            bool IsFloat=false;

            do{
                if(GetCurrentChar()==U'.')
                {
                    if(IsFloat)
                    {
                        Context->RaiseError(LineIndex,ColumnIndex,1,U"Invalid number");
                        return false;
                    }
                    else
                    {
                        IsFloat=true;
                    }
                }
                
                if(IsFloat)
                {
                    NumberStringAfterDot+=GetCurrentChar();
                }
                else
                {
                    NumberString+=GetCurrentChar();
                }
                GotoNextChar();
            }
            while(GetCurrentChar()>=U'0' && GetCurrentChar()<=U'9');

            //check if last token is a minus
            bool IsMinus=false;
            if(Context->Tokens.size()>0)
            {
                if(Context->Tokens.back()->Type==ETokenType::Minus)
                {
                    IsMinus=true;
                    //remove minus token
                    Context->Tokens.pop_back();
                }
            }

            std::shared_ptr<CToken> Token;
            if(IsFloat)
            {
                double Number= (NumberString+U'.'+NumberStringAfterDot).ToDouble(); //   std::stod(std::string(NumberString.begin(),NumberString.end())+"."+std::string(NumberStringAfterDot.begin(),NumberStringAfterDot.end()));
                if(IsMinus)
                {
                    Number=-Number;
                }

                Token=std::make_shared<CToken>(Number,SFilePosition(LineIndex,ColumnIndex,NumberString.GetLength()+NumberStringAfterDot.GetLength()+1));
            }
            else
            {
                int64_t Number=NumberString.ToInt64();
                if(IsMinus)
                {
                    Number=-Number;
                }
                Token=std::make_shared<CToken>((double)Number,SFilePosition(LineIndex,ColumnIndex,NumberString.GetLength()));
            }

            Context->Tokens.push_back(Token);
            return true;
        }



        case U'a': case U'b': case U'c': case U'd': case U'e': case U'f': case U'g': case U'h': case U'i': case U'j': case U'k': case U'l': case U'm': case U'n': case U'o': case U'p': case U'q': case U'r': case U's': case U't': case U'u': case U'v': case U'w': case U'x': case U'y': case U'z':
        case U'A': case U'B': case U'C': case U'D': case U'E': case U'F': case U'G': case U'H': case U'I': case U'J': case U'K': case U'L': case U'M': case U'N': case U'O': case U'P': case U'Q': case U'R': case U'S': case U'T': case U'U': case U'V': case U'W': case U'X': case U'Y': case U'Z':
        case U'_':
        {
            //parse identifier
            {
                C32String IdentifierString;
                do{
                    IdentifierString+=GetCurrentChar();
                    GotoNextChar();
                }
                while((GetCurrentChar()>=U'a' && GetCurrentChar()<=U'z') 
                || (GetCurrentChar()>=U'A' && GetCurrentChar()<=U'Z') 
                || (GetCurrentChar()>=U'0' && GetCurrentChar()<=U'9') 
                || GetCurrentChar()==U'_'
                );
                
                //check is string is _API
                if(Context->Tokens.size()>0)
                {
                    if(Context->Tokens.back()->Type==ETokenType::Class || Context->Tokens.back()->Type==ETokenType::Struct)
                    {
                        if(IdentifierString.EndsWith(U"_API"))
                        {
                            auto ExportAPIToken= std::make_shared<CToken>(ETokenType::EXPORT_API,SFilePosition(LineIndex,ColumnIndex- IdentifierString.GetLength() +1,IdentifierString.GetLength()));
                            ExportAPIToken->LiteralValue=IdentifierString;
                            Context->Tokens.push_back(ExportAPIToken);
                            return true;
                        }
                    }
                }

                if(!TryCreateKeywordToken(IdentifierString))
                {
                    auto IdentifierToken=std::make_shared<CToken>(ETokenType::Identifier,SFilePosition(LineIndex,ColumnIndex,IdentifierString.GetLength()));
                    IdentifierToken->LiteralValue=IdentifierString;
                    Context->Tokens.push_back(IdentifierToken);
                }
                return true;


            }
        }

        default:    
            //donot care
            GotoNextChar();
            return true;

    }

}

bool CTokenGenerator::TryCreateKeywordToken(C32String InWord)
{
    switch(InWord[0])
    {
        case U'R':
        {
            if(InWord==U"RENUM")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RENUM,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if (InWord==U"RSTRUCT")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RSTRUCT,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if (InWord==U"RCLASS")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RCLASS,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"RINTERFACE")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RINTERFACE,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"ROBJECT")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::ROBJECT,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"RFIELD")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RFIELD,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"RPROPERTY")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RPROPERTY,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"RFUNCTION")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::RFUNCTION,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else
            {
                return false;
            }
        }
        case U'G':
        {
            // if(InWord==U"WHENGINE_API")
            // {
            //     Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::EXPORT_API,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
            //     return true;
            // }
            // else
            {
                return false;
            }            
        }


        case U'a':
        {
            if(InWord==U"abstract")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Abstract,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"and")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::And,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else
            {
                return false;
            }

            break;

        }
        case U'b':
        {
            if(InWord==U"break")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Break,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else
            {
                return false;
            }
            break;
        }

        case U'c':
        {
            if(InWord==U"class")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Class,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"const")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Const,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"continue")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Continue,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"case")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Case,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;                
            }
            else if(InWord==U"catch")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Catch,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;                   
            }
            else
            {
                return false;
            }
            break;
        }

        case U'd':
        {
            if(InWord==U"do")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Do,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"default")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Default,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else
            {
                return false;
            }

            break;
        }

        case U'e':
        {
            if(InWord==U"else")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Else,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"enum")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Enum,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"extern")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Extern,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"explicit")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Explicit,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else
            {
                return false;
            }
            break;
        }

        case U'f':
        {
            if(InWord==U"for")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::For,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;               
            }
            else if(InWord==U"false")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(false,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;               
            }
            else if(InWord==U"finally")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Finally,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;               
            }
            else if(InWord==U"foreach")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Foreach,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;               
            }
            else
            {
                return false;
            }
            break;
        }

        case U'g':
        case U'h':
            return false;

        case U'i':
        {
            if(InWord==U"if")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::If,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;                   
            }
            else if(InWord==U"interface")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Interface,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;                   
            }
            else
            {
                return false;
            }

        }

        case U'j':
        case U'k':
        case U'l':
        case U'm':
            return false;

        case U'n':
        {
            if(InWord==U"new")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::New,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"nullptr")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Nullptr,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"namespace")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Namespace,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }    
            else 
            {
                return false;
            }
        }

        case U'o':
        {
            if(InWord==U"override")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Override,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"operator")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Operator,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else 
            {
                return false;
            }

        }

        case U'p':
        {
            if(InWord==U"private")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Private,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"protected")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Protected,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"public")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Public,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else 
            {
                return false;
            }

        }

        case U'q':
            return false;

        case U'r':
        {
            if(InWord==U"return")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Return,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else 
            {
                return false;
            }

        }

        case U's':
        {
            if(InWord==U"struct")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Struct,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"static")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Static,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"switch")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Switch,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"sizeof")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Sizeof,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else 
            {
                return false;
            }            

        }

        case U't':
        {
            if(InWord==U"true")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(true,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"this")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::This,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"throw")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Throw,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"try")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Try,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else 
            {
                return false;
            }          
        }

        case U'u':
            return false;

        case U'v':
        {
            if(InWord==U"virtual")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Virtual,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else if(InWord==U"volatile")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::Volatile,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else 
            {
                return false;
            }            
        }

        case U'w':
        {
            if(InWord==U"while")
            {
                Context->Tokens.push_back(std::make_shared<CToken>(ETokenType::While,SFilePosition(LineIndex,ColumnIndex- InWord.GetLength() +1,InWord.GetLength())));
                return true;
            }
            else 
            {
                return false;
            }   


        }

        case U'x':
        case U'y':
        case U'z':
            return false;
    }

    return false;
}

std::optional<char32_t> CTokenGenerator::ReadEscapeChar()
{
    auto CurrentChar=GetCurrentChar();
    assert(CurrentChar==U'\\');

    GotoNextChar();

    auto NextChar=GetCurrentChar();

    switch (NextChar)
    {
        case U'\'':
            return U'\'';
        
        case U'\"':
            return U'\"';
        
        case U'?':
            return U'\?';
        
        case U'\\':
            return U'\\';
        
        case U'a':
            return U'\a';
        
        case U'b':
            return U'\b';
        
        case U'f':
            return U'\f';
        
        case U'n':
            return U'\n';
        
        case U'r':
            return U'\r';
        
        case U't':
            return U'\t';
        
        case U'v':
            return U'\v';
        
        case U'0':
            return U'\0';
    }

    Context->RaiseError(SFilePosition(LineIndex,ColumnIndex,1),U"Invalid escape char");
    return std::nullopt;
}

char32_t CTokenGenerator::GetCurrentChar() const
{
    return Context->Content[CharIndex];
}

char32_t CTokenGenerator::GetNextChar() const
{
    return Context->Content[CharIndex+1];
}

void CTokenGenerator::GotoNextChar()
{
    auto CurrentChar=GetCurrentChar();
   
    CharIndex++;

    if(CurrentChar==U'\n')
    {
        LineIndex++;
        ColumnIndex=0;

    }
    else
    {
        ColumnIndex++;
    }

}
